﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VolunteerHubAdapter
{
    class RecordHelper
    {
        private VolunteerHubHelper _vhHelper;
        private Models.Settings _settings;
        private List<Models.Event> _events;
        private int _eventIndex;
        private int _userIndex;
        private int _userGroupIndex;
        private List<Models.UserGroup> _userGroups;
        private int _count;

        public DateTime LastRunDate;

        public RecordHelper(VolunteerHubHelper vhHelper, Models.Settings settings)
        {
            _vhHelper = vhHelper;
            _settings = settings;
            LoadEvents();
            FilterRegistrations();
            if (_events.Count > 0)
                LoadUserGroups();
        }

        public int Count
        {
            get
            {
                return _count;
            }
        }

        public OmaticIO.Base.Record GetNextRecord()
        {
            OmaticIO.Base.Record record = null;

            if (_eventIndex < _events.Count)
            {
                Models.Event ev = _events[_eventIndex];
                if (_userGroupIndex < ev.UserGroupRegistrations.Count())
                {
                    Models.UserGroupRegistration group = ev.UserGroupRegistrations[_userGroupIndex];
                    Models.UserGroup groupDetails = _userGroups.Find(g => g.UserGroupUid == group.UserGroupUid);
                    if (_userIndex < group.UserRegistrations.Count())
                    {
                        Models.UserRegistration userRegistration = group.UserRegistrations[_userIndex];
                        Models.User user = _vhHelper.GetSpecificUser(userRegistration.UserUid);
                        this.LastRunDate = userRegistration.RegistrationDate;

                        record = LoadRecord(ev, groupDetails, userRegistration, user);

                        _userIndex += 1;
                        if (_userIndex == group.UserRegistrations.Count())
                        {
                            _userIndex = 0;
                            _userGroupIndex += 1;
                            if (_userGroupIndex == ev.UserGroupRegistrations.Count())
                            {
                                _userGroupIndex = 0;
                                _eventIndex += 1;
                            }
                        }
                    }
                }
            }
            return record;
        }

        #region Private Methods
        /// <summary>
        /// Loads all events into the _events list
        /// </summary>
        private void LoadEvents()
        {
            _events = new List<Models.Event>();
            //VolunteerHub only allows 50 events to be returned in one call, call the service multiple times until we no longer get 50 events each hit
            int pageIndex = 0;
            bool moreEventsExist = true;
            while (moreEventsExist)
            {
                List<Models.Event> events = _vhHelper.GetEvents(pageIndex);
                _events.AddRange(events);
                if (events.Count == 50)
                {
                    pageIndex += 1;
                }
                else
                {
                    moreEventsExist = false;
                }
            }
        }

        private void FilterRegistrations()
        {
            foreach (var e in _events)
            {
                foreach (var ugr in e.UserGroupRegistrations)
                {
                    ugr.UserRegistrations = ugr.UserRegistrations.Where(u => u.RegistrationDate > _settings.LastRunDate && u.RegistrationDate <= _settings.EndRunDate).ToArray();
                    _count += ugr.UserRegistrations.Count();
                }
                e.UserGroupRegistrations = e.UserGroupRegistrations.Where(ugr => ugr.UserRegistrations.Count() > 0).ToArray();
            }
            _events = _events.Where(e => e.UserGroupRegistrations.Count() > 0).ToList();
        }

        private void LoadUserGroups()
        {
            _userGroups = new List<Models.UserGroup>();
            //VolunteerHub only allows 50 groups to be returned in one call, call the service multiple times until we no longer get 50 groups each hit
            int pageIndex = 0;
            bool moreGroupsExist = true;
            while (moreGroupsExist)
            {
                List<Models.UserGroup> groups = _vhHelper.GetGroups(pageIndex);
                _userGroups.AddRange(groups);
                if (groups.Count == 50)
                {
                    pageIndex += 1;
                }
                else
                {
                    moreGroupsExist = false;
                }
            }
        }

        private OmaticIO.Base.Record LoadRecord(Models.Event ev, Models.UserGroup group, Models.UserRegistration userRegistration, Models.User user)
        {
            OmaticIO.Base.Record record;
            List<OmaticIO.Base.Field> fields = new List<OmaticIO.Base.Field>();

            fields.Add(new OmaticIO.Base.Field() { Name = "EventID", Value = ev.EventUid });
            fields.Add(new OmaticIO.Base.Field() { Name = "EventName", Value = ev.Name });
            fields.Add(new OmaticIO.Base.Field() { Name = "EventShortDescription", Value = ev.ShortDescription });
            fields.Add(new OmaticIO.Base.Field() { Name = "EventLongDescription", Value = ev.LongDescription });
            fields.Add(new OmaticIO.Base.Field() { Name = "StartTime", Value = ev.StartTime });
            fields.Add(new OmaticIO.Base.Field() { Name = "EndTime", Value = ev.EndTime });
            fields.Add(new OmaticIO.Base.Field() { Name = "Location", Value = ev.Location });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserGroupName", Value = group.Name });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserGroupDescription", Value = group.Description });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserRegistrationDate", Value = userRegistration.RegistrationDate });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserRegistrationHours", Value = userRegistration.Hours });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserRegistrationDeleted", Value = userRegistration.Deleted });
            fields.Add(new OmaticIO.Base.Field() { Name = "UserId", Value = user.UserId });
            fields.Add(new OmaticIO.Base.Field() { Name = "Username", Value = user.Username });

            foreach (var question in _vhHelper.Organization.Forms[0].FormQuestions)
            {
                var answer = user.FormAnswers.Where(a => a.FormQuestionUId == question.FormQuestionUid).FirstOrDefault();
                if ((answer != null) && (answer.FormQuestionUId != System.Guid.Empty))
                {
                    AddFieldsForAnswerType(fields, answer, question);
                }
                else
                {
                    AddBlankFieldsForAnswerType(fields, question);
                }
            }

            record = new OmaticIO.Base.Record(fields);
            return record;
        }

        private void AddBlankFieldsForAnswerType(List<OmaticIO.Base.Field> fields, Models.FormQuestion question)
        {
            switch (question.FormQuestionType)
            {
                case VolunteerHub.Data.Api.FormQuestionType.Address:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerAddress));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Boolean:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerBoolean));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Date:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerDate));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Integer:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerInteger));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Name:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerName));
                    break;

                default:
                    AddBlankFieldsToObject(fields, question, typeof(VolunteerHub.Data.Api.FormAnswerString));
                    break;
            }
        }

        private void AddFieldsForAnswerType(List<OmaticIO.Base.Field> fields, VolunteerHub.Data.Api.FormAnswer answer, Models.FormQuestion question)
        {
            switch (question.FormQuestionType)
            {
                case VolunteerHub.Data.Api.FormQuestionType.Address:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerAddress));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Boolean:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerBoolean));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Date:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerDate));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Integer:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerInteger));
                    break;

                case VolunteerHub.Data.Api.FormQuestionType.Name:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerName));
                    break;

                default:
                    AddFieldsToObject(fields, answer, question.Name, typeof(VolunteerHub.Data.Api.FormAnswerString));
                    break;
            }
        }

        private void AddBlankFieldsToObject(List<OmaticIO.Base.Field> fields, Models.FormQuestion question, Type type)
        {
            foreach (var prop in type.GetProperties())
            {
                if (prop.Name.ToUpper() != "FormQuestionUid".ToUpper())
                    fields.Add(new OmaticIO.Base.Field() { Name = question.Name + " - " + prop.Name, Value = string.Empty });
            }
        }

        private void AddFieldsToObject(List<OmaticIO.Base.Field> fields, VolunteerHub.Data.Api.FormAnswer answer, string questionName, Type type)
        {
            foreach (var prop in type.GetProperties())
            {
                if (prop.Name.ToUpper() != "FormQuestionUid".ToUpper())
                    fields.Add(new OmaticIO.Base.Field() { Name = questionName + " - " + prop.Name, Value = prop.GetValue(answer, null) });
            }
        }

        #endregion
    }
}
